package com.wdb.modules.quartz.utils;

import com.wdb.exception.BadRequestException;
import com.wdb.modules.quartz.domain.QuartzJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;

/**
 * @author: wendaobai@qq.com
 * @date: 2024/8/21 星期三 11:14
 */
@Slf4j
@Component
public class QuartzManage {

  private static final String JOB_NAME = "TASK_";
  @Resource Scheduler scheduler;

  /**
   * 立即执行job
   *
   * @param quartzJob /
   */
  public void runJobNow(QuartzJob quartzJob) {
    try {
      TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
      CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
      if (trigger == null) {
        addJob(quartzJob);
      }
      JobDataMap dataMap = new JobDataMap();
      dataMap.put(QuartzJob.JOB_KEY, quartzJob);
      JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
      scheduler.triggerJob(jobKey, dataMap);
    } catch (SchedulerException e) {
      log.error("定时任务执行失败", e);
      throw new BadRequestException("定时任务执行失败");
    }
  }

  public void addJob(QuartzJob quartzJob) {
    // 构建job信息
    try {
      JobDetail jobDetail =
          JobBuilder.newJob(ExecutionJob.class).withIdentity(JOB_NAME + quartzJob.getId()).build();
      // 通过触发器名和cron 表达式创建 Trigger
      Trigger cronTrigger =
          TriggerBuilder.newTrigger()
              .withIdentity(JOB_NAME + quartzJob.getId())
              .startNow()
              .withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
              .build();
      cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
      // 重置启动时间
      ((CronTriggerImpl) cronTrigger).setStartTime(new Date());
      // 执行定时任务

      scheduler.scheduleJob(jobDetail, cronTrigger);
      // 暂停任务
      if (quartzJob.getIsPause()) {
        pauseJob(quartzJob);
      }
    } catch (SchedulerException e) {
      log.info("xxx");
    }
  }

  /**
   * 暂停一个job
   *
   * @param quartzJob /
   */
  public void pauseJob(QuartzJob quartzJob) {
    try {
      JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
      scheduler.pauseJob(jobKey);
    } catch (Exception e) {
      log.error("定时任务暂停失败", e);
      throw new BadRequestException("定时任务暂停失败");
    }
  }

  /**
   * 恢复一个暂停的定时任务 如果任务的触发器不存在，则添加一个新的任务
   *
   * @param quartzJob 要恢复的定时任务对象
   * @throws BadRequestException 当恢复任务失败时抛出异常
   */
  public void resumeJob(QuartzJob quartzJob) {
    try {
      // 构建触发器的键，用于识别触发器
      TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
      // 从调度器中获取Cron触发器
      CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

      // 如果触发器不存在，则创建一个定时任务
      if (trigger == null) {
        addJob(quartzJob);
      }

      // 构建任务的键，用于识别任务
      JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
      // 恢复任务，使其重新执行
      scheduler.resumeJob(jobKey);
    } catch (Exception e) {
      // 记录日志错误信息
      log.error("恢复定时任务失败", e);
      // 抛出业务异常
      throw new BadRequestException("恢复定时任务失败");
    }
  }

  /**
   * 更新job cron表达式
   *
   * @param quartzJob 包含要更新的cron表达式和任务信息的对象
   */
  public void updateJobCron(QuartzJob quartzJob) {
    try {
      // 获取triggerKey，用于唯一标识一个触发器
      TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());

      // 通过triggerKey获取CronTrigger对象
      CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

      // 如果触发器不存在，则添加一个新的任务
      if (trigger == null) {
        addJob(quartzJob);
        // 再次获取触发器，确保其已经存在
        trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
      } else {
        // 更新触发器的cron表达式
        CronScheduleBuilder scheduleBuilder =
            CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
        // 重新构建触发器，并使用新的cron表达式
        trigger =
            trigger
                .getTriggerBuilder()
                .withIdentity(triggerKey)
                .withSchedule(scheduleBuilder)
                .build();
        // 重置任务启动时间
        ((CronTriggerImpl) trigger).setStartTime(new Date());
      }

      // 重新安排任务，使用新的触发器
      scheduler.rescheduleJob(triggerKey, trigger);

      // 如果任务需要暂停，则暂停任务
      if (quartzJob.getIsPause()) {
        pauseJob(quartzJob);
      }
    } catch (Exception e) {
      // 记录并抛出异常
      log.error("更新定时任务失败", e);
      throw new BadRequestException("更新定时任务失败");
    }
  }

  /**
   * 删除指定的定时任务
   *
   * @param quartzJob 要删除的定时任务对象，不能为空
   * @throws BadRequestException 当删除任务失败时抛出，提示用户操作非法
   */
  public void deleteJob(QuartzJob quartzJob) {
    // 构造JobKey，用于标识定时任务
    JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
    try {
      // 暂停指定的Job，确保在删除前任务已经停止执行
      scheduler.pauseJob(jobKey);
      // 删除指定的Job
      scheduler.deleteJob(jobKey);
    } catch (SchedulerException e) {
      // 记录删除任务失败的日志信息
      log.error("删除定时任务失败", e);
      // 抛出异常，通知调用方删除操作失败
      throw new BadRequestException("删除定时任务失败");
    }
  }
}
